﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ICSharpCode.WinFormsUI.Controls.Chart3D
{
    public class Vector2D
    {
        double _x, _y;

        public Vector2D(double x, double y)
        {
            _x = x; _y = y;
        }
        public Vector2D(PointF pt)
        {
            _x = pt.X;
            _y = pt.Y;
        }
        public Vector2D(PointF st, PointF end)
        {
            _x = end.X - st.X;
            _y = end.Y - st.Y;
        }

        public double X
        {
            get { return _x; }
            set { _x = value; }
        }

        public double Y
        {
            get { return _y; }
            set { _y = value; }
        }

        public double Magnitude
        {
            get { return Math.Sqrt(X * X + Y * Y); }
        }

        public static Vector2D operator +(Vector2D v1, Vector2D v2)
        {
            return new Vector2D(v1.X + v2.X, v1.Y + v2.Y);
        }

        public static Vector2D operator -(Vector2D v1, Vector2D v2)
        {
            return new Vector2D(v1.X - v2.X, v1.Y - v2.Y);
        }

        public static Vector2D operator -(Vector2D v)
        {
            return new Vector2D(-v.X, -v.Y);
        }

        public static Vector2D operator *(double c, Vector2D v)
        {
            return new Vector2D(c * v.X, c * v.Y);
        }

        public static Vector2D operator *(Vector2D v, double c)
        {
            return new Vector2D(c * v.X, c * v.Y);
        }

        public static Vector2D operator /(Vector2D v, double c)
        {
            return new Vector2D(v.X / c, v.Y / c);
        }

        // 向量叉积
        // A * B =|A|.|B|.sin(angle AOB)
        public double CrossProduct(Vector2D v)
        {
            return _x * v.Y - v.X * _y;
        }

        // 向量点积
        // A. B=|A|.|B|.cos(angle AOB)
        public double DotProduct(Vector2D v)
        {
            return _x * v.X + _y * v.Y;
        }

        /// <summary>
        /// 利用矢量叉积判断是顺时针
        /// </summary>
        /// <param name="pt1"></param>
        /// <param name="pt2"></param>
        /// <param name="pt3"></param>
        /// <returns></returns>
        public static bool IsClockwise(PointF pt1, PointF pt2, PointF pt3)
        {
            Vector2D V21 = new Vector2D(pt2, pt1);
            Vector2D v23 = new Vector2D(pt2, pt3);
            return V21.CrossProduct(v23) < 0; // sin(angle pt1 pt2 pt3) > 0, 0<angle pt1 pt2 pt3 <180
        }

        /// <summary>
        /// 利用矢量叉积判断是逆时针 IsCCW
        /// </summary>
        /// <param name="pt1"></param>
        /// <param name="pt2"></param>
        /// <param name="pt3"></param>
        /// <returns></returns>
        public static bool IsCounterClockwise(PointF pt1, PointF pt2, PointF pt3)
        {
            Vector2D V21 = new Vector2D(pt2, pt1);
            Vector2D v23 = new Vector2D(pt2, pt3);
            return V21.CrossProduct(v23) > 0;  // sin(angle pt2 pt1 pt3) < 0, 180<angle pt2 pt1 pt3 <360
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pt"></param>
        /// <param name="lnA"></param>
        /// <param name="lnB"></param>
        /// <returns></returns>
        public static double DistancePointLine(PointF pt, PointF lnA, PointF lnB)
        {
            Vector2D v1 = new Vector2D(lnA, lnB);
            Vector2D v2 = new Vector2D(lnA, pt);
            v1 /= v1.Magnitude;
            return Math.Abs(v2.CrossProduct(v1));
        }

        /// <summary>
        /// 向量旋转
        /// </summary>
        /// <param name="Degree"></param>
        public void Rotate(int Degree)
        {
            double radian = Degree * Math.PI / 180.0;
            double sin = Math.Sin(radian);
            double cos = Math.Cos(radian);
            double nx = _x * cos - _y * sin;
            double ny = _x * sin + _y * cos;
            _x = nx;
            _y = ny;
        }

        public PointF ToPointF()
        {
            return new PointF((float)_x, (float)_y);
        }

    }
}
